package cn.metafoo.common.utils.monitor;

import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

/**
 * IP地址工具
 *
 * @Author: fatto
 * @create: 2023/3/27 16:13
 */
@Slf4j
public class IPUtil {
    private final static String UN_KNOWN_IP = "unknown";
    /**
     * 获取客户端ip
     * @return str
     */
    public static String getClientIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");

        if (ip == null || ip.length() == 0 || UN_KNOWN_IP.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || UN_KNOWN_IP.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || UN_KNOWN_IP.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }

        if (ip == null || ip.length() == 0 || UN_KNOWN_IP.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }

        if (ip == null || ip.length() == 0 || UN_KNOWN_IP.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        return ip;
    }

    public static String getClientIpAddr() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (servletRequestAttributes == null) {
            return null;
        }
        HttpServletRequest request = servletRequestAttributes.getRequest();
        return getClientIpAddr(request);
    }

    public static String getServerInnerIp() {
        // docker 启动时会传入该参数
        String ipAddr = System.getenv("SERVER_IP");
        if (StrUtil.isNotEmpty(ipAddr)) {
            return ipAddr;
        } else {
            return getLocalIp();
        }
    }

    private static String getSystemIpv4Linux(String name) {
        try {
            String ip = "";
            NetworkInterface networkInterface = NetworkInterface.getByName(name);
            Enumeration<InetAddress> inetAddress = networkInterface.getInetAddresses();
            InetAddress currentAddress = inetAddress.nextElement();
            while (inetAddress.hasMoreElements()) {
                currentAddress = inetAddress.nextElement();
                if (currentAddress instanceof Inet4Address && !currentAddress.isLoopbackAddress()) {
                    ip = currentAddress.toString();
                    break;
                }
            }
            if (ip.startsWith("/")) {
                ip = ip.substring(1);
            }
            return ip;
        } catch (Exception e) {
            log.error("NetWorkCard: {}, Exception Info: {}", name, e.getMessage());
            return null;
        }
    }

    private static String getLocalIp() {
        String localIp = null;
        String netIp = null;
        try {
            Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
            InetAddress ip = null;
            boolean finded = false;
            do {
                NetworkInterface ni = netInterfaces.nextElement();
                Enumeration<InetAddress> address = ni.getInetAddresses();
                while (address.hasMoreElements()) {
                    ip = address.nextElement();
                    if ((!ip.isSiteLocalAddress()) && (!ip.isLoopbackAddress()) && (!ip.getHostAddress().contains(":"))) {
                        netIp = ip.getHostAddress();
                        finded = true;
                        break;
                    }
                    if ((ip.isSiteLocalAddress()) && (!ip.isLoopbackAddress()) && (!ip.getHostAddress().contains(":"))) {
                        localIp = ip.getHostAddress();
                    }
                }
                if (!netInterfaces.hasMoreElements()) {
                    break;
                }
            } while (!finded);
        } catch (SocketException e) {
            e.printStackTrace();
        }
        if ((netIp != null) && (!"".equals(netIp))) {
            return netIp;
        }
        return localIp;
    }
}
